#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2022/4/25 22:41
# @Author  : Tang Yiwei
# @Email   : yiweitang@yunify.com
# @File    : file_util.py
# @Software: PyCharm

import csv
import errno
import json as jsmod
import os
import shutil
import sys
import tempfile
import time
from pathlib import Path

import openpyxl
import yaml
from openpyxl.styles import Font

from utils.log import log


def zip_folder(folder_path, zip_file_path):
    """
    快速压缩成zip文件
    :param folder_path:
    :param zip_file_path:
    :return:
    """
    try:
        shutil.make_archive(zip_file_path, 'zip', folder_path)
        return Path(zip_file_path).with_suffix('.zip')
    except Exception as e:
        log.error(f'压缩文件异常: {e}')
        return ''


def get_temp_dir():
    """
    获取系统的临时目录
    :return:
    """
    return tempfile.gettempdir()


def create_temp_file(content):
    """
    创建临时文件
    :param content: 写入临时文件的内容
    :return:
    """
    with tempfile.TemporaryFile() as fp:
        # 写入临时文件
        fp.write(content)
        # 将文件移动到指针开始处，准备读取文件
        fp.seek(0)


def write_content_to_file(file, content):
    """
    写入内容到文件
    :param content:
    :return:
    """
    try:
        with open(file, mode="w", encoding="utf-8") as fp:
            fp.write(content)
    except Exception as e:
        raise e


def create_temp_dir():
    """
    创建临时目录
    :return:
    """
    with tempfile.TemporaryDirectory() as tmpdirname:
        print(f"创建临时目录:{tmpdirname}")
        return tmpdirname


def get_file_info(filepath: str = ""):
    """
    获取文件的详细信息
    索引号:fileinfo.st_ino
    设备名:fileinfo.st_dev
    文件大小:fileinfo.st_size
    最后一次访问时间:fileinfo.st_atime
    最后一次修改时间:fileinfo.st_mtime
    最后一次状态变化时间:fileinfo.st_ctime
    :param filepath:文件路径
    :return:
    """
    return os.stat(filepath)


def format_byte(number: int = 0):
    """
    格式化文件大小的函数
    :param number: 要格式化的字节数
    :return:
    """
    for scale, label in [(1024 * 1024 * 1024, "GB"), (1024 * 1024, "MB"), (1024, "KB")]:
        if number >= scale:
            return "%.2f %s" % (number * 1.0 / scale, label)
        elif number == 1:
            return "1 字节"
        else:
            byte = "%.2f" % (number or 0)
    # 去掉结尾的.00，并且加上单位字节
    return (byte[:-3] if byte.endswith(".00") else byte) + " 字节"


def get_files(patterns: list = [], path: str = "") -> list:
    """
    递归获取指定的文件路径
    :param patterns: 指定的文件类型,例如.txt、.py等
    :param path: 需要检查的路径
    :return:
    """
    all_files = []
    p = Path(path)
    for item in patterns:
        file_name = p.rglob(f"**/*{item}")
        all_files.extend(file_name)
    files = []
    for file in all_files:
        files.append(str(file))
    return files


def generate_txt_file(filepath: str = "", filesize: int = 0):
    """
    生成指定大小的txt文件，单位:Byte
    :param filepath:
    :param filesize:
    :return:
    """
    if filepath == "":
        raise ValueError("filepath can't be empty")
    localtime = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
    filename = localtime + "_" + str(filesize) + "_Byte.txt"
    file = filepath + filename
    with open(file, "w") as f:
        for i in range(filesize):
            f.write("1")
    return file


def rmtree_dir(dir_path):
    """
    删除指定目录
    :param dir_path:
    :return:
    """
    try:
        shutil.rmtree(dir_path)
        log.info(f"目录 {dir_path} 及其内容已成功删除。")
    except OSError as e:
        log.error(f"删除目录 {dir_path} 时出错: {e.strerror}")


def json_dump(obj, indent=None):
    """Dump an object to json string, only basic types are supported.
    @return json string or `None` if failed
    '{"int":1,"none":null,"str":"string"}'
    """
    try:
        jstr = jsmod.dumps(obj, separators=(",", ":"), indent=indent, sort_keys=True)
    except Exception:
        jstr = None
    return jstr


def json_load(json):
    """Load from json string and create a new python object
    @return object or `None` if failed
    {u'int': 1, u'none': None, u'str': u'string'}
    """
    try:
        obj = jsmod.loads(json)
    except Exception:
        obj = None
    return obj


def read_file(file, mode="r"):
    """
    读取本地文件
    :param file:
    :param mode:
    :return:
    """
    try:
        with open(file, mode) as f:
            content = f.read()
    except Exception as e:
        log.error(f"读取文件:{file}时异常,原因:{e}")
        return None
    return content


def mkdir(path):
    try:
        os.makedirs(path)
    except OSError as exc:  # Python >2.5
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise


def handle_yaml(file_name):
    try:
        yaml_data = yaml.safe_load(open(file_name, encoding="utf-8"))
    except Exception as e:
        raise e
    else:
        return yaml_data


def yaml_syntax_check(dir):
    """
    检查指定的路径下的yaml文件语法是否正确
    :param dir: yaml文件路径
    :return:
    """
    yaml_file = []
    filelist = os.listdir(dir)
    for i in filelist:
        current_path = os.path.join(dir, i)
        if os.path.isfile(current_path):
            if current_path.endswith(".yaml"):
                yaml_file.append(os.path.join(os.path.abspath(dir), i))
        if os.path.isdir(current_path):
            yaml_syntax_check(current_path)
    for ym in yaml_file:
        try:
            with open(ym, "r", encoding="utf-8") as f:
                cont = f.read()
            yaml.warnings({"YAMLLoadWarning": False})
            yaml.load(cont, Loader=yaml.FullLoader)
        except Exception as e:
            log.error(f"{ym} file syntax format error,place check syntax......")
            log.error(e)
            sys.exit(1)


class ExcelUtil:
    def __init__(self, file_path, sheet_name):
        self.file_path = file_path
        self.sheet_name = sheet_name
        try:
            self.workbook = openpyxl.load_workbook(self.file_path)
            self.sheet = self.workbook[self.sheet_name]
        except Exception as e:
            print(e)

        self.font_color = Font(color=None)
        self.font_style = Font(name=None)

        self.font_style_dict = {
            "microsoft_accor_black": "微软雅黑",
            "regular_script": "楷体",
            "song_typeface": "宋体",
        }

        self.rgb_dict = {"red": "FF0000", "green": "FF008B00", "blcak": "000000"}

    def __enter__(self):
        try:
            self.workbook = openpyxl.load_workbook(self.file_path)
            self.sheet = self.workbook[self.sheet_name]
        except Exception as e:
            print(e)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file_path:
            self.save_excel()

    def read_excel(self):
        """
        根据sheet_name读取excel
        :param sheet_name:
        :return:
        """
        all_rows = []

        max_row = self.sheet.max_row
        max_column = self.sheet.max_column

        key = []
        for line in range(1, max_column + 1):
            key.append(self.sheet.cell(row=1, column=line).value)  # 表格的标题

        for i in range(1, max_row + 1):
            tmpList = []
            if i < 2:
                continue
            for j in range(1, max_column + 1):
                tmpList.append(self.sheet.cell(row=i, column=j).value)
            all_rows.append(tmpList)

        rows_dict = []
        for value in all_rows:
            lis = dict(zip(key, value))
            rows_dict.append(lis)
        return rows_dict

    def write_excel(self, row=None, column=None, content=None, color="blcak"):
        """
        根据excel的sheet name 写入内容
        :param row: 写入的某一行
        :param column: 写入的某一列
        :param content:写入的内容
        :param content:写入文本的背景颜色
        :return:
        """
        self.sheet.cell(row, column).font = Font(color=self.rgb_dict[color])
        self.sheet.cell(row, column).value = content

    def save_excel(self):
        self.workbook.save(self.file_path)


class CsvUtil:
    def __init__(self, csv_file_path=None):
        self.csv_file_path = csv_file_path

    def read_csv(self):
        """
        对csv进行读取操作，结果以list形式返回
        :return: temList
        """
        temList = []
        with open(self.csv_file_path, "r", encoding="utf-8") as f:
            read = csv.reader(f)
            for i in read:
                temList.append(i)
        return temList

    def write_csv_list(self, headers=None, rows=None):
        """
        对csv以list数据类型
        headers:列头名称
        rows:写入的数据
        :return: None
        # example :
        # headers = ['class', 'name', 'sex', 'height', 'year']
        # rows = [
        #     [1, 'xiaoming', 'male', 168, 23],
        #     [1, 'xiaohong', 'female', 162, 22],
        #     [2, 'xiaozhang', 'female', 163, 21],
        #     [2, 'xiaoli', 'male', 158, 21]]
        """
        try:
            with open(
                    self.csv_file_path, "w", encoding="utf-8", newline=""
            ) as f:  # 出现空行需要加=> newline=''
                write = csv.writer(f)
                write.writerow(headers)
                write.writerows(rows)
                print("csv 写入完成!")
        except PermissionError as e:
            raise e
        except Exception as e:
            raise e

    def write_csv_dict(self, headers=None, rows=None):
        """
        写csv以dict数据类型
        :param headers:
        :param rows:
        :return:
        # example :
        # headers = ['class', 'name', 'sex', 'height', 'year']
        # rows = [
        #     {'class': 1, 'name': 'xiaoming', 'sex': 'male', 'height': 168, 'year': 23},
        #     {'class': 2, 'name': 'xiaohong', 'sex': 'female', 'height': 162, 'year': 22},
        #     {'class': 3, 'name': 'xiaozhang', 'sex': 'female', 'height': 163, 'year': 21},
        #     {'class': 4, 'name': 'xiaoli', 'sex': 'male', 'height': 158, 'year': 21}]
        """
        try:
            with open(self.csv_file_path, "w", encoding="utf-8", newline="") as f:
                write = csv.DictWriter(f, headers)
                write.writeheader()
                write.writerows(rows)
                print("csv 写入完成!")
        except PermissionError as e:
            raise e
        except Exception as e:
            raise e
